include "SLA.inc"
include "QoSRegistry.inc"
include "QoSWeaver.inc"

--TravelAgent2

val AirlineList = ["Airline 1", "Airline 2"]
val HotelList = ["Hotel A", "Hotel B"]
def QoSsite(sitex) = QoS(sitex.function(),sitex.QoSID())

--BestQoS and simulation utilities
def bestQ(comparer,publisher) =  head(sortBy(comparer,collect(publisher)))
def cat() = if (Random(1)=1) then "Economy" else "Premium"
val simElaspedTime = Rclock()

--Sites declared
def GenerateOrder(SalesOrder,Budget) = Dictionary() >GenerateInvoice> GenerateInvoice.TravelAgent := SalesOrder.ordernumber? >> GenerateInvoice.acceptedTime := simElaspedTime.time() >> Println("Order "+GenerateInvoice.TravelAgent?+" accepted at time "+GenerateInvoice.acceptedTime?) >> (GenerateInvoice,Budget)
def inquireCost(List) = each(List) >sup> Dictionary() >ProductDetails> ProductDetails.Company := sup>> ProductDetails.cost := Random(50) >> ProductDetails
def inquireCategory(List) = each(List) >sup> Dictionary() >ProductDetails> ProductDetails.Company := sup >> ProductDetails.cost := Random(50) >> ProductDetails.category := cat() >> ProductDetails
def compareCost(x, y) = x.cost? <= y.cost?
def compareCategory(x, y) = if x.category?="Economy" then false else if y.category?="Economy" then true else compareCost(x, y)
def CheckBudget(GenerateInvoice,Budget) = if (GenerateInvoice.AirQuote?.cost? + GenerateInvoice.HotelQuote?.cost? <: Budget) then GenerateInvoice else (Println("Resubmit Order " +GenerateInvoice.TravelAgent?)>> Dictionary() >SalesOrder> SalesOrder.ordernumber:= GenerateInvoice.TravelAgent? >> (SalesOrder,GenerateOrder(SalesOrder,Budget)))
def timeout(x, t, SalesOrder) = Let(Some(x) | (Rwait(t) >> notifyFail(SalesOrder, "Timeout") >> None()))
def notifyFail(SalesOrder, reaSalesOrdern) = Println("Order "+SalesOrder.id?+" failed: "+reaSalesOrdern) >> stop

--QoS Aware Sites
def class AirlineCompany(GenerateInvoice,Cost) =
          def function() = bestQ(compareCost, defer(inquireCost,AirlineList)) >q> GenerateInvoice >> GenerateInvoice.AirQuote := q 
          def QoSID() =  "Airline"
          stop

def class HotelBooking(GenerateInvoice,Cost) = 
     def function() = bestQ(compareCategory, defer(inquireCategory,HotelList)) >q> GenerateInvoice >> GenerateInvoice.HotelQuote := q
     def QoSID() =  "Hotel"
     stop
          
 def class TravelAgent(SalesOrder,Budget,Cost,Latency) = 
    def function() =timeout((GenerateOrder(SalesOrder,Budget) >(GenerateInvoice,Budget)> QoSsite(AirlineCompany(GenerateInvoice,Cost)) >(_,AirQoS)> GenerateInvoice.AirQoS := AirQoS >> QoSsite(HotelBooking(GenerateInvoice,Cost)) >(_,HotelQoS)> GenerateInvoice.HotelQoS := HotelQoS  >> CheckBudget(GenerateInvoice,Budget)) , 10000, SalesOrder)  >Some(GenerateInvoice)> 
GenerateInvoice
   def QoSID()= "TAgent"
   stop


--Simulation  
def simulateOrders(50) = stop
def simulateOrders(n) = Dictionary() >SalesOrder> SalesOrder.ordernumber:= n >> SalesOrder
   | Rwait(Random(100)) >> simulateOrders(n+1)
   
simulateOrders(1) >SalesOrder> QoSsite(TravelAgent(SalesOrder,150,Cost,ResponseTime)) >(GenerateInvoice,QoS)> ((GenerateInvoice.TravelAgent?,QoS) >> Println("Invoice for order "+SalesOrder.ordernumber?+" presented at time "+simElaspedTime.time()) 
>> (GenerateInvoice.AirQoS?,GenerateInvoice.HotelQoS?) >([[aq]],[[hq]])> (aq,hq)>> (GenerateInvoice.TravelAgent?,append(QoS,[Cost(Items).QoSOplus(aq,hq)])))